// 版权所有2009 Go作者。保留所有权利。
// 此源代码的使用受BSD样式
// 许可证的约束，该许可证可以在许可证文件中找到。

// unicode包提供数据和函数来测试
// unicode代码点的某些属性。
package unicode

const (
	MaxRune         = '\U0010FFFF' // 最大有效Unicode代码点。
	ReplacementChar = '\uFFFD'     // 表示无效的代码点。
	MaxASCII        = '\u007F'     // 最大ASCII值。
	MaxLatin1       = '\u00FF'     // 最大拉丁语-1值。
)

// Range Table通过列出集合中的
// 代码点的范围来定义一组Unicode代码点。为了节省空间，这些范围分为两部分：一部分是16位范围，另一部分是32位范围。
// 这两个切片必须按顺序排列且不重叠。
// 此外，R32只应包含>=0x10000（1<<16）的值。
type RangeTable struct {
	R16         []Range16
	R32         []Range32
	LatinOffset int // R16中Hi<=MaxLatin1 
}

// 范围16表示16位Unicode码点的范围。范围从Lo到Hi 
// 包括在内，并具有指定的步幅。
type Range16 struct {
	Lo     uint16
	Hi     uint16
	Stride uint16
}

// Range32代表一系列Unicode代码点，当一个或多个值不适合16位时使用。范围从Lo到Hi 
// 包括在内，并具有指定的步幅。Lo和Hi必须始终大于等于1。
type Range32 struct {
	Lo     uint32
	Hi     uint32
	Stride uint32
}

// CaseRange表示用于简单（一个
// 代码点到一个代码点）大小写转换的一系列Unicode代码点。
// 范围从低到高，固定步幅为1。delta 
// 是要添加到代码点以达到
// 的代码点的数字，该字符的大小写不同。它们可能是负面的。如果为零，则
// 表示该字符在相应的大小写中。有一个特殊的
// 大小写表示交替对应的上下
// 对序列。它出现在一个固定的增量
// /{UpperLower，UpperLower，UpperLower}
// 常数UpperLower有一个不可能的增量值。
type CaseRange struct {
	Lo    uint32
	Hi    uint32
	Delta d
}

// SpecialCase表示特定于语言的大小写映射，例如土耳其语。
// 特殊情况的方法通过覆盖标准映射来定制。
type SpecialCase []CaseRange

// 错误（r）：没有完全大小写折叠的机制，也就是说，对于输入或输出中涉及多个符文的
// 字符。

// 索引到案例范围内的增量数组中，用于案例映射。
const (
	UpperCase = iota
	LowerCase
	TitleCase
	MaxCase
)

type d [MaxCase]rune // 为了使CaseRanges文本更短，

// 如果CaseRange的Delta字段是UpperLower，这意味着
// 这个CaseRange表示一个形式的序列（比如）
// Upper-Lower。
const (
	UpperLower = MaxRune + 1 // /（不能是有效的增量。）
)

// linearMax是非拉丁符文线性搜索的最大大小表。
// 通过运行“go test-calibrate”导出。
const linearMax = 18

// is16报告r是否在16位范围的排序切片中。
func is16(ranges []Range16, r uint16) bool {
	if len(ranges) <= linearMax || r <= MaxLatin1 {
		for i := range ranges {
			range_ := &ranges[i]
			if r < range_.Lo {
				return false
			}
			if r <= range_.Hi {
				return range_.Stride == 1 || (r-range_.Lo)%range_.Stride == 0
			}
		}
		return false
	}

	// 范围内的二进制搜索
	lo := 0
	hi := len(ranges)
	for lo < hi {
		m := lo + (hi-lo)/2
		range_ := &ranges[m]
		if range_.Lo <= r && r <= range_.Hi {
			return range_.Stride == 1 || (r-range_.Lo)%range_.Stride == 0
		}
		if r < range_.Lo {
			hi = m
		} else {
			lo = m + 1
		}
	}
	return false
}

// is32报告r是否在32位范围的排序切片中。
func is32(ranges []Range32, r uint32) bool {
	if len(ranges) <= linearMax {
		for i := range ranges {
			range_ := &ranges[i]
			if r < range_.Lo {
				return false
			}
			if r <= range_.Hi {
				return range_.Stride == 1 || (r-range_.Lo)%range_.Stride == 0
			}
		}
		return false
	}

	// 范围内的二进制搜索
	lo := 0
	hi := len(ranges)
	for lo < hi {
		m := lo + (hi-lo)/2
		range_ := ranges[m]
		if range_.Lo <= r && r <= range_.Hi {
			return range_.Stride == 1 || (r-range_.Lo)%range_.Stride == 0
		}
		if r < range_.Lo {
			hi = m
		} else {
			lo = m + 1
		}
	}
	return false
}

// Is报告符文是否在指定的范围表中。
func Is(rangeTab *RangeTable, r rune) bool {
	r16 := rangeTab.R16
	// 比较as uint32以正确处理负面符文。
	if len(r16) > 0 && uint32(r) <= uint32(r16[len(r16)-1].Hi) {
		return is16(r16, uint16(r))
	}
	r32 := rangeTab.R32
	if len(r32) > 0 && r >= rune(r32[0].Lo) {
		return is32(r32, uint32(r))
	}
	return false
}

func isExcludingLatin(rangeTab *RangeTable, r rune) bool {
	r16 := rangeTab.R16
	// 比较as uint32以正确处理负面符文。
	if off := rangeTab.LatinOffset; len(r16) > off && uint32(r) <= uint32(r16[len(r16)-1].Hi) {
		return is16(r16[off:], uint16(r))
	}
	r32 := rangeTab.R32
	if len(r32) > 0 && r >= rune(r32[0].Lo) {
		return is32(r32, uint32(r))
	}
	return false
}

// IsUpper报告符文是否为大写字母。
func IsUpper(r rune) bool {
	// 请参见IsGraphic中的注释。
	if uint32(r) <= MaxLatin1 {
		return properties[uint8(r)]&pLmask == pLu
	}
	return isExcludingLatin(Upper, r)
}

// IsLower报告符文是否为小写字母。
func IsLower(r rune) bool {
	// 请参见IsGraphic中的注释。
	if uint32(r) <= MaxLatin1 {
		return properties[uint8(r)]&pLmask == pLl
	}
	return isExcludingLatin(Lower, r)
}

// IsTitle报告符文是否为标题字母。
func IsTitle(r rune) bool {
	if r <= MaxLatin1 {
		return false
	}
	return isExcludingLatin(Title, r)
}

// 使用指定的大小写映射映射符文。
// 它还报告caseRange是否包含r的映射。
func to(_case int, r rune, caseRange []CaseRange) (mappedRune rune, foundMapping bool) {
	if _case < 0 || MaxCase <= _case {
		return ReplacementChar, false // 与任何
	}
	// 范围内的二进制搜索
	lo := 0
	hi := len(caseRange)
	for lo < hi {
		m := lo + (hi-lo)/2
		cr := caseRange[m]
		if rune(cr.Lo) <= r && r <= rune(cr.Hi) {
			delta := cr.Delta[_case]
			if delta > MaxRune {
				// 以上下顺序（总是以
				// 大写字母开头）一样合理，真正的delta看起来总是这样的：
				// /{0，1，0}大写（下一个是小写）
				// /{-1，0，-1}小写（上一个，标题是前一个）
				// 从
				// 序列开始的偶数偏移处的字符是大写；奇数偏移处的值较低。
				// 可以通过清除或设置序列偏移量中的低位
				// 来完成正确的映射。
				// 大写和TitleCase的常量是偶数，而小写
				// 是奇数，所以我们从_case中取低位。
				return rune(cr.Lo) + ((r-rune(cr.Lo))&^1 | rune(_case&1)), true
			}
			return r + delta, true
		}
		if r < rune(cr.Lo) {
			hi = m
		} else {
			lo = m + 1
		}
	}
	return r, false
}

// 将符文映射到指定的大小写：大写、小写或标题。
func To(_case int, r rune) rune {
	r, _ = to(_case, r, CaseRanges)
	return r
}

// ToUpper将符文映射为大写。
func ToUpper(r rune) rune {
	if r <= MaxASCII {
		if 'a' <= r && r <= 'z' {
			r -= 'a' - 'A'
		}
		return r
	}
	return To(UpperCase, r)
}

// ToLower将符文映射为小写。
func ToLower(r rune) rune {
	if r <= MaxASCII {
		if 'A' <= r && r <= 'Z' {
			r += 'a' - 'A'
		}
		return r
	}
	return To(LowerCase, r)
}

// ToTitle将符文映射到title case。
func ToTitle(r rune) rune {
	if r <= MaxASCII {
		if 'a' <= r && r <= 'z' { // title case是ASCII的大写字母
			r -= 'a' - 'A'
		}
		return r
	}
	return To(TitleCase, r)
}

// ToUpper将符文映射为大写字母，优先考虑特殊映射。
func (special SpecialCase) ToUpper(r rune) rune {
	r1, hadMapping := to(UpperCase, r, []CaseRange(special))
	if r1 == r && !hadMapping {
		r1 = ToUpper(r)
	}
	return r1
}

// ToTitle将符文映射到title case，优先考虑特殊映射。
func (special SpecialCase) ToTitle(r rune) rune {
	r1, hadMapping := to(TitleCase, r, []CaseRange(special))
	if r1 == r && !hadMapping {
		r1 = ToTitle(r)
	}
	return r1
}

// ToLower将符文映射为小写，优先考虑特殊映射。
func (special SpecialCase) ToLower(r rune) rune {
	r1, hadMapping := to(LowerCase, r, []CaseRange(special))
	if r1 == r && !hadMapping {
		r1 = ToLower(r)
	}
	return r1
}

// caseOrbit在表格中定义。像…一样去。现在所有的
// 条目都适合uint16，所以使用uint16。如果这种情况发生变化，编译
// 将失败（复合文本中的常量将不适合uint16）
// 并且这里的类型可以更改为uint32。
type foldPair struct {
	From uint16
	To   uint16
}

// SimpleFold在Unicode代码点上迭代，相当于
// Unicode定义的简单大小写折叠。在相当于符文（包括符文本身）的代码点
// 中，如果存在，SimpleFold返回
// 最小符文>r，否则最小符文>=0。
// 如果r不是有效的Unicode代码点，SimpleFold（r）返回r.
// 
// 例如：
// SimpleFold（'a'）='a'
// SimpleFold（'a'）='a'
// 
// SimpleFold（'K'）='K'
// SimpleFold（'K'）='，K) 
// SimpleFold（'\u212A'）='K'
// 
// SimpleFold（'1'）='1'
// 
// SimpleFold（-2）=-2 
// 
func SimpleFold(r rune) rune {
	if r < 0 || r > MaxRune {
		return r
	}

	if int(r) < len(asciiFold) {
		return rune(asciiFold[r])
	}

	// 特殊情况请查阅caseOrbit表格。
	lo := 0
	hi := len(caseOrbit)
	for lo < hi {
		m := lo + (hi-lo)/2
		if rune(caseOrbit[m].From) < r {
			lo = m + 1
		} else {
			hi = m
		}
	}
	if lo < len(caseOrbit) && rune(caseOrbit[lo].From) == r {
		return rune(caseOrbit[lo].To)
	}

	// 未指定折叠。这是一个单元素或两元素的
	// 等价类，包含符文和ToLower（符文）
	// 和ToUpper（符文），如果它们与符文不同。
	if l := ToLower(r); l != r {
		return l
	}
	return ToUpper(r)
}
